Package com.golden.gamedev.engine.audio

Source Code of com.golden.gamedev.engine.audio.JOrbisOggRenderer$OggPlayer

/*
* Copyright (c) 2008 Golden T Studios.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package com.golden.gamedev.engine.audio;

// JFC
import java.io.InputStream;
import java.net.URL;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;

import com.jcraft.jogg.Packet;
import com.jcraft.jogg.Page;
import com.jcraft.jogg.StreamState;
import com.jcraft.jogg.SyncState;
import com.jcraft.jorbis.Block;
import com.jcraft.jorbis.Comment;
import com.jcraft.jorbis.DspState;
import com.jcraft.jorbis.Info;

import com.golden.gamedev.engine.BaseAudioRenderer;

/**
* Play Ogg sound (*.ogg) using JOrbis library, <br>
* JOrbis library is available to download at <a
* href="http://www.jcraft.com/jorbis/" target="_blank">
* http://www.jcraft.com/jorbis/</a>.
* <p>
*
* Make sure the downloaded library is included into your game classpath before
* using this audio renderer.
* <p>
*
* <b>Note: GTGE is not associated in any way with JOrbis, this class is only
* interfacing JOrbis to be used in GTGE. <br>
* This class is created and has been tested to be working properly using
* <em>JOrbis 0.0.14</em>.</b>
* <p>
*
* How-to-use <code>JOrbisRenderer</code> in GTGE Frame Work :
*
* <pre>
* public class YourGame extends Game {
*  
*   protected void initEngine() {
*     super.initEngine();
*     // set sound effect to use ogg
*     bsSound.setSampleRenderer(new JOrbisRenderer());
*     // set music to use ogg
*     bsMusic.setSampleRenderer(new JOrbisRenderer());
*   }
* }
* </pre>
*/
public class JOrbisOggRenderer extends BaseAudioRenderer {
 
  private static final int BUFSIZE = 4096 * 2;
 
  private static int convsize = JOrbisOggRenderer.BUFSIZE * 2;
  private static byte[] convbuffer = new byte[JOrbisOggRenderer.convsize];
 
  private SyncState oy;
  private StreamState os;
  private Page og;
  private Packet op;
  private Info vi;
  private Comment vc;
  private DspState vd;
  private Block vb;
 
  private byte[] buffer;
  private int bytes;
 
  private int format;
  private int rate;
  private int channels;
  private SourceDataLine outputLine;
 
  private int frameSizeInBytes;
  private int bufferLengthInBytes;
 
  private OggPlayer player;
  private InputStream bitStream;
 
  /** ************************************************************************* */
  /** ***************************** CONSTRUCTOR ******************************* */
  /** ************************************************************************* */
 
  /**
   * Creates a new instance of <code>JOrbisOggRenderer</code>.
   */
  public JOrbisOggRenderer() {
  }
 
  /**
   * <i>Please refer to super class method documentation.</i>
   */
  public boolean isAvailable() {
    return true;
  }
 
  /**
   * <i>Please refer to super class method documentation.</i>
   */
  protected void playSound(URL audiofile) {
    try {
      this.bitStream = audiofile.openStream();
    }
    catch (Exception e) {
      e.printStackTrace();
      return;
    }
   
    this.player = new OggPlayer();
    this.player.setDaemon(true);
    this.player.start();
  }
 
  /**
   * <i>Please refer to super class method documentation.</i>
   */
  protected void replaySound(URL audiofile) {
    this.playSound(audiofile);
  }
 
  /**
   * <i>Please refer to super class method documentation.</i>
   */
  protected void stopSound() {
    if (this.player != null) {
      try {
        this.outputLine.drain();
        this.outputLine.stop();
        this.outputLine.close();
        if (this.bitStream != null) {
          this.bitStream.close();
        }
      }
      catch (Exception e) {
      }
    }
   
    this.player = null;
  }
 
  /**
   * <i>Please refer to super class method documentation.</i>
   */
  public boolean isVolumeSupported() {
    return false;
  }
 
  private SourceDataLine getOutputLine(int channels, int rate) {
    if (this.outputLine != null || this.rate != rate
            || this.channels != channels) {
      if (this.outputLine != null) {
        this.outputLine.drain();
        this.outputLine.stop();
        this.outputLine.close();
      }
     
      this.init_audio(channels, rate);
      this.outputLine.start();
    }
    return this.outputLine;
  }
 
  private void init_audio(int channels, int rate) {
    try {
      AudioFormat audioFormat = new AudioFormat((float) rate, 16,
              channels, true, // PCM_Signed
              false // littleEndian
      );
      DataLine.Info info = new DataLine.Info(SourceDataLine.class,
              audioFormat, AudioSystem.NOT_SPECIFIED);
      if (!AudioSystem.isLineSupported(info)) {
        System.out.println("Line " + info + " not supported.");
        return;
      }
     
      try {
        this.outputLine = (SourceDataLine) AudioSystem.getLine(info);
        // outputLine.addLineListener(this);
        this.outputLine.open(audioFormat);
      }
      catch (LineUnavailableException e) {
        System.out.println("Unable to open the sourceDataLine: " + e);
        return;
      }
      catch (IllegalArgumentException e) {
        System.out.println("Illegal Argument: " + e);
        return;
      }
     
      this.frameSizeInBytes = audioFormat.getFrameSize();
      int bufferLengthInFrames = this.outputLine.getBufferSize()
              / this.frameSizeInBytes / 2;
      this.bufferLengthInBytes = bufferLengthInFrames
              * this.frameSizeInBytes;
     
      this.rate = rate;
      this.channels = channels;
    }
    catch (Exception e) {
      System.out.println(e);
    }
  }
 
  private void init_jorbis() {
    this.oy = new SyncState();
    this.os = new StreamState();
    this.og = new Page();
    this.op = new Packet();
   
    this.vi = new Info();
    this.vc = new Comment();
    this.vd = new DspState();
    this.vb = new Block(this.vd);
   
    this.buffer = null;
    this.bytes = 0;
   
    this.oy.init();
  }
 
  private class OggPlayer extends Thread {
   
    public final void run() {
      JOrbisOggRenderer.this.init_jorbis();
     
      loop: while (true) {
        int eos = 0;
       
        int index = JOrbisOggRenderer.this.oy
                .buffer(JOrbisOggRenderer.BUFSIZE);
        JOrbisOggRenderer.this.buffer = JOrbisOggRenderer.this.oy.data;
        try {
          JOrbisOggRenderer.this.bytes = JOrbisOggRenderer.this.bitStream
                  .read(JOrbisOggRenderer.this.buffer, index,
                          JOrbisOggRenderer.BUFSIZE);
        }
        catch (Exception e) {
          JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
          System.err.println(e);
          return;
        }
        JOrbisOggRenderer.this.oy.wrote(JOrbisOggRenderer.this.bytes);
       
        if (JOrbisOggRenderer.this.oy
                .pageout(JOrbisOggRenderer.this.og) != 1) {
          if (JOrbisOggRenderer.this.bytes < JOrbisOggRenderer.BUFSIZE) {
            break;
          }
          JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
          System.err
                  .println("Input does not appear to be an Ogg bitstream.");
          return;
        }
       
        JOrbisOggRenderer.this.os.init(JOrbisOggRenderer.this.og
                .serialno());
        JOrbisOggRenderer.this.os.reset();
       
        JOrbisOggRenderer.this.vi.init();
        JOrbisOggRenderer.this.vc.init();
       
        if (JOrbisOggRenderer.this.os.pagein(JOrbisOggRenderer.this.og) < 0) {
          // error; stream version mismatch perhaps
          JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
          System.err
                  .println("Error reading first page of Ogg bitstream data.");
          return;
        }
       
        if (JOrbisOggRenderer.this.os
                .packetout(JOrbisOggRenderer.this.op) != 1) {
          // no page? must not be vorbis
          JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
          System.err.println("Error reading initial header packet.");
          break;
          // return;
        }
       
        if (JOrbisOggRenderer.this.vi.synthesis_headerin(
                JOrbisOggRenderer.this.vc, JOrbisOggRenderer.this.op) < 0) {
          // error case; not a vorbis header
          JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
          System.err
                  .println("This Ogg bitstream does not contain Vorbis audio data.");
          return;
        }
       
        int i = 0;
       
        while (i < 2) {
          while (i < 2) {
            int result = JOrbisOggRenderer.this.oy
                    .pageout(JOrbisOggRenderer.this.og);
            if (result == 0) {
              break; // Need more data
            }
            if (result == 1) {
              JOrbisOggRenderer.this.os
                      .pagein(JOrbisOggRenderer.this.og);
              while (i < 2) {
                result = JOrbisOggRenderer.this.os
                        .packetout(JOrbisOggRenderer.this.op);
                if (result == 0) {
                  break;
                }
                if (result == -1) {
                  JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
                  System.err
                          .println("Corrupt secondary header.  Exiting.");
                  // return;
                  break loop;
                }
                JOrbisOggRenderer.this.vi.synthesis_headerin(
                        JOrbisOggRenderer.this.vc,
                        JOrbisOggRenderer.this.op);
                i++;
              }
            }
          }
         
          index = JOrbisOggRenderer.this.oy
                  .buffer(JOrbisOggRenderer.BUFSIZE);
          JOrbisOggRenderer.this.buffer = JOrbisOggRenderer.this.oy.data;
          try {
            JOrbisOggRenderer.this.bytes = JOrbisOggRenderer.this.bitStream
                    .read(JOrbisOggRenderer.this.buffer, index,
                            JOrbisOggRenderer.BUFSIZE);
          }
          catch (Exception e) {
            JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
            System.err.println(e);
            return;
          }
         
          if (JOrbisOggRenderer.this.bytes == 0 && i < 2) {
            JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
            System.err
                    .println("End of file before finding all Vorbis headers!");
            return;
          }
         
          JOrbisOggRenderer.this.oy
                  .wrote(JOrbisOggRenderer.this.bytes);
        }
       
        JOrbisOggRenderer.convsize = JOrbisOggRenderer.BUFSIZE
                / JOrbisOggRenderer.this.vi.channels;
       
        JOrbisOggRenderer.this.vd
                .synthesis_init(JOrbisOggRenderer.this.vi);
        JOrbisOggRenderer.this.vb.init(JOrbisOggRenderer.this.vd);
       
        double[][][] _pcm = new double[1][][];
        float[][][] _pcmf = new float[1][][];
        int[] _index = new int[JOrbisOggRenderer.this.vi.channels];
       
        JOrbisOggRenderer.this.getOutputLine(
                JOrbisOggRenderer.this.vi.channels,
                JOrbisOggRenderer.this.vi.rate);
       
        while (eos == 0) {
          while (eos == 0) {
           
            if (JOrbisOggRenderer.this.status != BaseAudioRenderer.PLAYING) {
              try {
                // outputLine.drain();
                // outputLine.stop();
                // outputLine.close();
                JOrbisOggRenderer.this.bitStream.close();
              }
              catch (Exception e) {
                System.err.println(e);
              }
             
              return;
            }
           
            int result = JOrbisOggRenderer.this.oy
                    .pageout(JOrbisOggRenderer.this.og);
            if (result == 0) {
              break; // need more data
            }
            if (result == -1) { // missing or corrupt data at this
              // page position
              // System.err.println("Corrupt or missing data in
              // bitstream; continuing...");
            }
            else {
              JOrbisOggRenderer.this.os
                      .pagein(JOrbisOggRenderer.this.og);
              while (true) {
                result = JOrbisOggRenderer.this.os
                        .packetout(JOrbisOggRenderer.this.op);
                if (result == 0) {
                  break; // need more data
                }
                if (result == -1) { // missing or corrupt data
                  // at this page position
                  // no reason to complain; already complained
                  // above
                }
                else {
                  // we have a packet. Decode it
                  int samples;
                  if (JOrbisOggRenderer.this.vb
                          .synthesis(JOrbisOggRenderer.this.op) == 0) { // test
                    // for
                    // success!
                    JOrbisOggRenderer.this.vd
                            .synthesis_blockin(JOrbisOggRenderer.this.vb);
                  }
                  while ((samples = JOrbisOggRenderer.this.vd
                          .synthesis_pcmout(_pcmf, _index)) > 0) {
                    double[][] pcm = _pcm[0];
                    float[][] pcmf = _pcmf[0];
                    boolean clipflag = false;
                    int bout = (samples < JOrbisOggRenderer.convsize ? samples
                            : JOrbisOggRenderer.convsize);
                   
                    // convert doubles to 16 bit signed ints
                    // (host order) and
                    // interleave
                    for (i = 0; i < JOrbisOggRenderer.this.vi.channels; i++) {
                      int ptr = i * 2;
                      // int ptr=i;
                      int mono = _index[i];
                      for (int j = 0; j < bout; j++) {
                        int val = (int) (pcmf[i][mono
                                + j] * 32767.);
                        if (val > 32767) {
                          val = 32767;
                          clipflag = true;
                        }
                        if (val < -32768) {
                          val = -32768;
                          clipflag = true;
                        }
                        if (val < 0) {
                          val = val | 0x8000;
                        }
                        JOrbisOggRenderer.convbuffer[ptr] = (byte) (val);
                        JOrbisOggRenderer.convbuffer[ptr + 1] = (byte) (val >>> 8);
                        ptr += 2 * (JOrbisOggRenderer.this.vi.channels);
                      }
                    }
                    JOrbisOggRenderer.this.outputLine
                            .write(
                                    JOrbisOggRenderer.convbuffer,
                                    0,
                                    2
                                            * JOrbisOggRenderer.this.vi.channels
                                            * bout);
                    JOrbisOggRenderer.this.vd
                            .synthesis_read(bout);
                  }
                }
              }
              if (JOrbisOggRenderer.this.og.eos() != 0) {
                eos = 1;
              }
            }
          }
         
          if (eos == 0) {
            index = JOrbisOggRenderer.this.oy
                    .buffer(JOrbisOggRenderer.BUFSIZE);
            JOrbisOggRenderer.this.buffer = JOrbisOggRenderer.this.oy.data;
            try {
              JOrbisOggRenderer.this.bytes = JOrbisOggRenderer.this.bitStream
                      .read(JOrbisOggRenderer.this.buffer, index,
                              JOrbisOggRenderer.BUFSIZE);
            }
            catch (Exception e) {
              JOrbisOggRenderer.this.status = BaseAudioRenderer.ERROR;
              System.err.println(e);
              return;
            }
            if (JOrbisOggRenderer.this.bytes == -1) {
              break;
            }
            JOrbisOggRenderer.this.oy
                    .wrote(JOrbisOggRenderer.this.bytes);
            if (JOrbisOggRenderer.this.bytes == 0) {
              eos = 1;
            }
          }
        }
       
        JOrbisOggRenderer.this.os.clear();
        JOrbisOggRenderer.this.vb.clear();
        JOrbisOggRenderer.this.vd.clear();
        JOrbisOggRenderer.this.vi.clear();
      }
     
      JOrbisOggRenderer.this.oy.clear();
     
      try {
        if (JOrbisOggRenderer.this.bitStream != null) {
          JOrbisOggRenderer.this.bitStream.close();
        }
      }
      catch (Exception e) {
      }
     
      JOrbisOggRenderer.this.status = BaseAudioRenderer.END_OF_SOUND;
    }
  }
 
  // protected void finalize() throws Throwable {
  // System.out.println("finalization = "+this);
  // super.finalize();
  // }
 
  /**
   * Testing the OGG Player.
   */
  public static void main(String args[]) {
    BaseAudioRenderer ogg = new JOrbisOggRenderer();
   
    String music1 = "file:///d:/golden t studios/trash/sound/MUSIC2.ogg";
   
    if (args != null) {
      if (args.length >= 1) {
        music1 = args[0];
      }
    }
   
    // test first song
    try {
      ogg.play(new URL(music1));
    }
    catch (Exception e) {
      e.printStackTrace();
    }
   
    // hear some music
    int update = 0;
    while (ogg.getStatus() == BaseAudioRenderer.PLAYING) {
      try {
        Thread.sleep(1000);
      }
      catch (InterruptedException e) {
      }
     
      System.out.println(update++);
     
      if (update > 6) {
        ogg.stop();
      }
    }
   
    // first song stopped
    System.out.println("end-song");
   
    // try {
    // ogg.play(new URL("file:///d:/golden t studios/trash/songtitle.ogg"));
    // } catch (Exception e) { e.printStackTrace(); }
   
    // play it again
    ogg.play();
   
    // wait until complete
    while (ogg.getStatus() == BaseAudioRenderer.PLAYING) {
      try {
        Thread.sleep(1000);
      }
      catch (InterruptedException e) {
      }
     
      System.out.println(update++);
    }
   
    System.out.println("end-song 2");
  }
 
}
TOP

Related Classes of com.golden.gamedev.engine.audio.JOrbisOggRenderer$OggPlayer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.